/*
   @Copyright:LibreOJ
   @Author:   tjyemail
   @Problem:  https://loj.ac/problem/101
   @Language: C++
   @Datetime: 20-08-14 14:07
   */
// Dinic, time O(E*V^2) 26ms

#include <bits/stdc++.h>
using namespace std;

#define VERTEX 102
// adjacency list
struct Edge {
	int v, rev; // vertex, reverse edge position
	long long cap;
	Edge(int v=0, int rev=0, long long cap=0):v(v), rev(rev), cap(cap){}
};
vector<Edge> edges[VERTEX];
inline void add(int a, int b, int c) {
	edges[a].push_back(Edge(b, edges[b].size(), c));
	edges[b].push_back(Edge(a, edges[a].size()-1, 0));
}
int deeps[VERTEX], curs[VERTEX]; // current available edge position

bool bfs(int v, int s, int t) {
	memset(deeps, 0, sizeof(int)*(v+1));
	deeps[s] = 1;
	queue<int> vs;
	for(vs.push(s); !vs.empty(); vs.pop()) {
		s = vs.front();
		for(const Edge &ek : edges[s]) {
			if (deeps[ek.v] || ek.cap<1) continue;
			deeps[ek.v] = deeps[s] + 1;
			vs.push(ek.v);
		}
	}
	return deeps[t]; // check if it has path s->t
}

long long dfs(int v, int s, int t, long long cap=INT_MAX) {
	if (cap==0 || s==t) return cap;
	long long flow = 0, cur = 0;
	for(int k=curs[s]; k<edges[s].size() && flow!=cap; ++k) {
		curs[s] = k; // record current available edge position
		Edge &ek = edges[s][k];
		if (deeps[ek.v]!=deeps[s]+1 || ek.cap<1) continue;
		cur = dfs(v, ek.v, t, min(cap-flow, ek.cap));
		ek.cap -= cur;
		edges[ek.v][ek.rev].cap += cur; // reverse edge
		flow += cur;
	}
	return flow;
}

void dinic(int v, int s, int t) {
	long long flow = 0;
	while(bfs(v, s, t)) {
		memset(curs, 0, sizeof(int)*(v+1));
		flow += dfs(v, s, t);
	}
	printf("%lld\n", flow);
}

int main()
{
	int v, e, s, t, a, b, c; // vertex edge, source -> target
	scanf("%d %d %d %d", &v, &e, &s, &t);
	for(int i=0; i++<e; ) {
		scanf("%d %d %d", &a, &b, &c); // a->b, capacity
		add(a, b, c);
	}
	dinic(v, s, t);
	return 0;
}
